D:\a\scloud-dns\scloud-dns\src\dns\packet\authority\mod.rs
Line | Count | Source |
1 | | use crate::dns::q_class::DNSClass; |
2 | | use crate::dns::q_name::parse_qname; |
3 | | use crate::dns::q_type::DNSRecordType; |
4 | | use crate::exceptions::SCloudException; |
5 | | |
6 | | #[derive(PartialEq, Debug)] |
7 | | pub(crate) struct AuthoritySection { |
8 | | pub(crate) q_name: String, |
9 | | pub(crate) q_type: DNSRecordType, |
10 | | pub(crate) q_class: DNSClass, |
11 | | pub(crate) ttl: u32, |
12 | | pub(crate) ns_name: String, |
13 | | } |
14 | | |
15 | | impl AuthoritySection { |
16 | | /// Deserialize one AuthoritySection (NS record) and return (section, consumed_bytes) |
17 | | /// |
18 | | /// # Exemple : |
19 | | /// ``` |
20 | | /// use crate::dns::packet::authority::AuthoritySection; |
21 | | /// use crate::dns::q_type::DNSRecordType; |
22 | | /// use crate::dns::q_class::DNSClass; |
23 | | /// |
24 | | /// // example.com NS ns1.example.com |
25 | | /// let raw_authority: Vec<u8> = vec![ |
26 | | /// 0x07, b'e', b'x', b'a', b'm', b'p', b'l', b'e', |
27 | | /// 0x03, b'c', b'o', b'm', |
28 | | /// 0x00, // End of QNAME |
29 | | /// 0x00, 0x02, // TYPE = NS |
30 | | /// 0x00, 0x01, // CLASS = IN |
31 | | /// 0x00, 0x00, 0x0e, 0x10, // TTL = 3600 |
32 | | /// 0x00, 0x11, // RDLENGTH = 17 |
33 | | /// 0x03, b'n', b's', b'1', |
34 | | /// 0x07, b'e', b'x', b'a', b'm', b'p', b'l', b'e', |
35 | | /// 0x03, b'c', b'o', b'm', |
36 | | /// 0x00, // End of NSNAME |
37 | | /// ]; |
38 | | /// |
39 | | /// let (authority, consumed) = |
40 | | /// AuthoritySection::from_bytes(&raw_authority, 0).unwrap(); |
41 | | /// |
42 | | /// assert_eq!(authority.q_name, "example.com"); |
43 | | /// assert_eq!(authority.q_type, DNSRecordType::NS); |
44 | | /// assert_eq!(authority.q_class, DNSClass::IN); |
45 | | /// assert_eq!(authority.ttl, 3600); |
46 | | /// assert_eq!(authority.ns_name, "ns1.example.com"); |
47 | | /// assert_eq!(consumed, raw_authority.len()); |
48 | | /// ``` |
49 | 5 | pub(crate) fn from_bytes( |
50 | 5 | buf: &[u8], |
51 | 5 | offset: usize, |
52 | 5 | ) -> Result<(AuthoritySection, usize), SCloudException> { |
53 | 5 | let (q_name, mut pos) = parse_qname(buf, offset).unwrap(); |
54 | | |
55 | 5 | if buf.len() < pos + 10 { |
56 | 2 | return Err(SCloudException::SCLOUD_AUTHORITY_DESERIALIZATION_FAILED_BUF_TOO_SHORT); |
57 | 3 | } |
58 | | |
59 | 3 | let q_type = DNSRecordType::try_from(u16::from_be_bytes([buf[pos], buf[pos + 1]])).unwrap(); |
60 | 3 | pos += 2; |
61 | | |
62 | 3 | let q_class = DNSClass::try_from(u16::from_be_bytes([buf[pos], buf[pos + 1]])).unwrap(); |
63 | 3 | pos += 2; |
64 | | |
65 | 3 | let ttl = u32::from_be_bytes([buf[pos], buf[pos + 1], buf[pos + 2], buf[pos + 3]]); |
66 | 3 | pos += 4; |
67 | | |
68 | 3 | let rdlength = u16::from_be_bytes([buf[pos], buf[pos + 1]]); |
69 | 3 | pos += 2; |
70 | | |
71 | 3 | if buf.len() < pos + rdlength as usize { |
72 | 1 | return Err( |
73 | 1 | SCloudException::SCLOUD_AUTHORITY_DESERIALIZATION_FAILED_RDATA_OUT_OF_BOUNDS, |
74 | 1 | ); |
75 | 2 | } |
76 | | |
77 | 2 | let (ns_name, _) = parse_qname(buf, pos).unwrap(); |
78 | | |
79 | 2 | pos += rdlength as usize; |
80 | | |
81 | 2 | Ok(( |
82 | 2 | AuthoritySection { |
83 | 2 | q_name, |
84 | 2 | q_type, |
85 | 2 | q_class, |
86 | 2 | ttl, |
87 | 2 | ns_name, |
88 | 2 | }, |
89 | 2 | pos - offset, |
90 | 2 | )) |
91 | 5 | } |
92 | | |
93 | | /// Serialize the AuthoritySection (NS record) into bytes |
94 | | /// |
95 | | /// # Exemple : |
96 | | /// ``` |
97 | | /// use crate::dns::packet::authority::AuthoritySection; |
98 | | /// use crate::dns::q_type::DNSRecordType; |
99 | | /// use crate::dns::q_class::DNSClass; |
100 | | /// |
101 | | /// let authority = AuthoritySection { |
102 | | /// q_name: "example.com".to_string(), |
103 | | /// q_type: DNSRecordType::NS, |
104 | | /// q_class: DNSClass::IN, |
105 | | /// ttl: 3600, |
106 | | /// ns_name: "ns1.example.com".to_string(), |
107 | | /// }; |
108 | | /// |
109 | | /// let bytes = authority.to_bytes().unwrap(); |
110 | | /// |
111 | | /// // NAME + TYPE + CLASS + TTL + RDLENGTH + RDATA |
112 | | /// assert!(bytes.len() > 20); |
113 | | /// ``` |
114 | 1 | pub(crate) fn to_bytes(&self) -> Result<Vec<u8>, SCloudException> { |
115 | 1 | let mut buf = Vec::new(); |
116 | | |
117 | 3 | for label in self.q_name.split('.')1 { |
118 | 3 | buf.push(label.len() as u8); |
119 | 3 | buf.extend_from_slice(label.as_bytes()); |
120 | 3 | } |
121 | 1 | buf.push(0x00); |
122 | | |
123 | 1 | let qtype_u16 = |
124 | 1 | u16::try_from(self.q_type).expect("Cannot convert AuthoritySection q_type to u16"); |
125 | 1 | buf.extend_from_slice(&qtype_u16.to_be_bytes()); |
126 | | |
127 | 1 | let qclass_u16 = u16::try_from(self.q_class).unwrap(); |
128 | 1 | buf.extend_from_slice(&qclass_u16.to_be_bytes()); |
129 | | |
130 | 1 | buf.extend_from_slice(&self.ttl.to_be_bytes()); |
131 | | |
132 | 1 | let mut rdata = Vec::new(); |
133 | 4 | for label in self.ns_name.split('.')1 { |
134 | 4 | rdata.push(label.len() as u8); |
135 | 4 | rdata.extend_from_slice(label.as_bytes()); |
136 | 4 | } |
137 | 1 | rdata.push(0x00); |
138 | | |
139 | 1 | buf.extend_from_slice(&(rdata.len() as u16).to_be_bytes()); |
140 | 1 | buf.extend_from_slice(&rdata); |
141 | | |
142 | 1 | Ok(buf) |
143 | 1 | } |
144 | | } |